This script reads in both PBMC and Liver Seurat objects, and generates select figures used in the manuscript.

Prepare objects

Load libraries

library(Seurat)
library(scClustViz)
library(ggplot2)
library(dplyr)
library(rcartocolor)
library(SeuratWrappers)

Read in liver map

sobj <- readRDS("~/Dropbox/Zoe/scf_version/analysis/healthy_sc/seurat_objects/dropletQC_filtered/allIntegrated_cca_kanchor5_noBiopsyHeps_dropletQCFiltered.RDS")
res <- "integrated_snn_res.1.4"
Idents(sobj) <- res
tissue <- "liver"

Read in PBMC map

load("~/Dropbox/Zoe/scf_version/analysis/healthy_sc/seurat_objects/no_dropletQC/integrated_PBMC_cca_kanchor5_scClustViz.RData")
sobj <- scSeurat
res <- "integrated_snn_res.0.6"
Idents(sobj) <- res
tissue <- "PBMC"

Visualization of metadata

UMAP with no cluster numbers

plot <- DimPlot(sobj, label = FALSE) & NoLegend()
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_clusters_noLabels.pdf", sep = ""))
plot
dev.off()
png 
  2 

UMAP with cluster numbers

plot <- DimPlot(sobj, label = TRUE)
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_clusters_labels.pdf", sep = ""))
plot
dev.off()
png 
  2 

Map with SCINA-generated cell-type labels

DimPlot(sobj, group.by = "scina_labels_refined", label = TRUE) & NoLegend()

Map with general cell-type labels for paper

plot <- DimPlot(sobj, group.by = "general_cell_labels",
        label = TRUE, repel = TRUE) +
  ggtitle(NULL)
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_general_cell_labels.pdf", sep = ""),
    height = 8,
    width = 12)
plot
dev.off()
png 
  2 

Map grouping by general cell type labels but with no labels on plot

plot <- DimPlot(sobj, group.by = "general_cell_labels") +
  ggtitle(NULL) &
  NoLegend()
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_general_cell_labels_noLabels.pdf", 
          sep = ""))
plot
dev.off()
png 
  2 

Map with original identities

plot <- DimPlot(sobj, group.by = "orig.ident",
        cols = carto_pal(length(levels(as.factor(sobj$orig.ident))), "Safe")) +
  ggtitle(NULL)
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_orig_idents.pdf", 
          sep = ""))
plot
dev.off()
png 
  2 

Barplot with original identities on a cluster-level grouping:

# Meta data to plot:
df <- sobj@meta.data
# Check what column the cluster identities are in
col <- which(colnames(df) == res)
# Order clusters
df[,col] <- factor(Idents(sobj),
                             levels = c(sort(as.numeric(levels(Idents(sobj))))))
# Basic plot of clusters by replicate
ggplot(df, aes(x = get(res), fill = orig.ident)) +
  geom_bar() +
  theme(axis.text = element_text(size = 7))

# Plot as proportion or percentage of cluster
ggplot(df, aes(x = get(res), fill = orig.ident)) +
  geom_bar(position = "fill") +
  theme(axis.text = element_text(size = 7))

Barplot with original identities on a grouped by general cell labels:

df <- sobj@meta.data
plot1 <- ggplot(df, aes(x = general_cell_labels, fill = orig.ident)) +
  geom_bar() +
  scale_fill_carto_d(name = NULL, palette = "Safe") +
  theme_bw() +
  theme(axis.text = element_text(size = 8),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title.x = element_blank()) +
  ylab("Number of cells")
plot1
pdf(paste("./figures/", tissue, "/", tissue, "_barplot_orig_ident_counts.pdf", 
          sep = ""))
plot1
dev.off()
png 
  2 

# Plot as proportion or percentage of cluster
plot2 <- ggplot(df, aes(x = general_cell_labels, fill = orig.ident)) +
  geom_bar(position = "fill") +
  scale_fill_carto_d(name = NULL, palette = "Safe") +
  theme_bw() +
  theme(axis.text = element_text(size = 8),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title.x = element_blank()) +
  ylab("Proportion of cells")
plot2
pdf(paste("./figures/", tissue, "/", tissue, "_barplot_orig_ident_proportions.pdf", 
          sep = ""))
plot2
dev.off()
png 
  2 

Dotplots

Generate dotplot with specific markers

DotPlot(sobj,
        assay = "SCT",
        features = c("PTPRC", "CALCRL", "NKG7", "CD3E", "MARCO", "LYZ-1", "CD19", "MS4A1", "STAB2")
        ) +
  ggtitle("Select features for liver map")

Heatmaps

Calculate markers for general cell labels then reset resolution

Idents(sobj) <- "general_cell_labels"
sobj_markers <- RunPrestoAll(sobj, 
                             only.pos = TRUE, 
                             min.pct = 0.25, 
                             logfc.threshold = 0.25)
Calculating cluster B cells
Calculating cluster Lymphocytes 3
Calculating cluster Monocytes 1
Calculating cluster Erythrocytes
Calculating cluster Lymphocytes 1
Calculating cluster Monocytes 2
Calculating cluster Lymphocytes 2
Calculating cluster Lymphocytes 5
Calculating cluster Monocytes 3
Calculating cluster Monocytes 4
Calculating cluster Plasma B cells
Calculating cluster Unknown
Calculating cluster Mast cells
Calculating cluster Lymphocytes 4
Calculating cluster Hematopoietic stem cells
Calculating cluster Megakaryocytes
sobj_markers %>%
    group_by(cluster) %>%
    slice_max(n = 2, order_by = avg_log2FC)
Idents(sobj) <- res

Save markers

groups = "general_cell_labels"
write.table(sobj_markers,
            file = paste("./figures/", tissue, "/",
                         tissue, "_markers_", groups, ".tsv", 
                         sep = ""),
            quote = FALSE,
            sep = "\t",
            row.names = FALSE,
            col.names = TRUE)

Generate heatmap with top 5 markers grouping by general cell types

# Remove mikado genes from marker list
sobj_markers <- sobj_markers[grep("mikado", rownames(sobj_markers), invert = TRUE),]
sobj_markers %>%
    group_by(cluster) %>%
    top_n(n = 5, wt = avg_log2FC) -> top
# If liver, select fewer cells
if (tissue == "liver") {
  cells <- sample(colnames(sobj), size = 30000)
} else if (tissue == "PBMC") {
  cells <- colnames(sobj)
}
DoHeatmap(sobj, features = top$gene, group.by = "general_cell_labels", size = 3, 
          angle = 90, cells = cells) +
  NoLegend() +
  theme(text = element_text(size = 7))

Make PDF of heatmap

groups <- "general_cell_labels"
pdf(paste("./figures/", tissue, "/", tissue, "_heatmap_", groups, ".pdf", sep = ""),
    height = 11,
    width = 7)
DoHeatmap(sobj, features = top$gene, group.by = "general_cell_labels", size = 2, 
          angle = 90, cells = cells) +
  NoLegend() +
  theme(text = element_text(size = 7))
dev.off()
null device 
          1 

Feature plots

Make specific plots with specific genes. The genes we are interested in include: PTPRC, CALCRL, NKG7, CD3E, MARCO, LYZ, CD19, MS4A1, STAB2, ALB, CD4, CD8A, CLEC4G, CD5L, C1QB, ACTA2, VWF, IGLL5, CD68. Can also plot in italics.

geneCode <- "sct_LYZ-1" # Woodchuck-specific nomenclature for this genome
gene <- "LYZ"
mapType <- "Liver"
FeaturePlot(sobj, features = geneCode) +
  ggtitle(paste(gene, "-", mapType, "map"))

FeaturePlot(sobj, features = geneCode) +
  ggtitle(bquote(~italic(.(gene))))

Another version of the feature plot that outputs genes in italics

if (tissue == "PBMC") {
 geneCodes <- c("sct_PTPRC","sct_NKG7","sct_CD14",
               "sct_CD3E","sct_MARCO","sct_LYZ-1",
               "sct_CD19","sct_MS4A1","sct_STAB2",
               "sct_CD4","sct_CD8A", "sct_XCL1;XCL2",
               "sct_CD5L","sct_C1QB", "sct_LEF1",
               "sct_ACTA2","sct_VWF","sct_IGLL5-1",
               "sct_CD68","sct_FCGR3A;FCGR3B","sct_TOP2A")
 genes <- c("PTPRC","NKG7","CD14","CD3E","MARCO","LYZ",
           "CD19","MS4A1","STAB2","CD4","CD8A", "XCL1;XCL2",
           "CD5L","C1QB","LEF1","ACTA2","VWF","IGLL5","CD68",
           "FCGR3A;FCGR3B","TOP2A") 
} else if (tissue == "liver") {
  geneCodes <- c("sct_Ptprc","sct_CALCRL","sct_NKG7",
                 "sct_CD3E","sct_MARCO","sct_LYZ-1",
                 "sct_CD19","sct_MS4A1","sct_STAB2",
                 "sct_ALB-1","sct_CD4","sct_CD8A",
                 "sct_CLEC4G","sct_CD5L","sct_C1QB",
                 "sct_ACTA2","sct_VWF","sct_IGLL5-1",
                 "sct_CD68","sct_XCL1;XCL2","sct_LEF1",
                 "sct_RSPO3","sct_MECOM")
  genes <- c("PTPRC","CALCRL","NKG7","CD3E","MARCO","LYZ",
             "CD19","MS4A1","STAB2","ALB","CD4","CD8A",
             "CLEC4G","CD5L","C1QB","ACTA2","VWF","IGLL5","CD68",
             "XCL1;XCL2","LEF1","RSPO3","MECOM") 
}
for(num in 2:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Cell-population-specific markers

Plot marker genes for specific cell populations

Endothelial cells:

geneCodes <- c("sct_STAB2","sct_ITGA1","sct_CD55","sct_LYVE1",
               "sct_CD34","sct_VWF","sct_IFITM3;IFITM2;IFITM1","sct_RSPO3",
               "sct_MECOM","sct_Mecom","sct_CALCRL","sct_LOC114089654",
               "sct_RAMP2","sct_BST2","sct_CLEC4G","sct_CTSV;CTSL",
               "sct_STAB1","sct_PLAC9","sct_PECAM1","sct_WNT2",
               "sct_MYL6","sct_NR2F2")
genes <- c("STAB2","ITGA1","CD55","LYVE1",
           "CD34","VWF","IFITM3","RSPO3",
           "MECOM","Mecom","CALCRL","LOC114089654",
           "RAMP2","BST2","CLEC4G","CTSV;CTSL",
           "STAB1","PLAC9","PECAM1","WNT2",
           "MYL6","NR2F2") 
for(num in 1:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Lymphocytes:

geneCodes <- c("sct_CD3D","sct_CD3E","sct_CD8A","sct_NKG7",
               "sct_KLRD1","sct_KLRB1","sct_GZMA","sct_LEF1",
               "sct_IL7R-1","sct_EOMES","sct_TIGIT","sct_XCL1;XCL2",
               "sct_TOX","sct_CTLA4","sct_CD4","sct_GZMK")
genes <- c("CD3D","CD3E","CD8A","NKG7",
           "KLRD1","KLRB1","GZMA","LEF1",
           "IL7R","EOMES","TIGIT","XCL1;XCL2",
           "TOX","CTLA4","CD4","GZMK") 
for(num in 1:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Mesenchyme:

geneCodes <- c("sct_HHIP","sct_COL1A2","sct_COL3A1","sct_IGFBP7",
               "sct_IGFBP3","sct_DCN","sct_COL1A1","sct_SPARC",
               "sct_RBP1", "sct_CALCRL")
genes <- c("HHIP","COL1A2","COL3A1","IGFBP7",
           "IGFBP3","DCN","COL1A1","SPARC",
           "RBP1","CALCRL") 
for(num in 1:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Cholangiocytes:

geneCodes <- c("sct_KRT19","sct_CFTR","sct_EPCAM","sct_SLC4A4")
genes <- c("KRT19","CFTR","EPCAM","SLC4A4") 
for(num in 1:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Look at zonation gene signatures:

cv_genes <- c("FETUB","HMGCS1","CYP2E1","GLUD1;GLUD2","CYP1A2",
              "RGN","INMT","COMT","FDPS","SPR-1")
cv_genes
 [1] "FETUB"       "HMGCS1"      "CYP2E1"      "GLUD1;GLUD2" "CYP1A2"      "RGN"        
 [7] "INMT"        "COMT"        "FDPS"        "SPR-1"      
pp_genes <- c("Saa2;Saa1-1","HAMP","APOA1","APOC2","CRYL1",
              "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B","MT-ATP6","UROC1",
              "APOA2","MT-CO3")
pp_genes
 [1] "Saa2;Saa1-1"                   "HAMP"                         
 [3] "APOA1"                         "APOC2"                        
 [5] "CRYL1"                         "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B"
 [7] "MT-ATP6"                       "UROC1"                        
 [9] "APOA2"                         "MT-CO3"                       

Correlation plots

Generate heatmaps comparing woodchuck clusters with various datasets

Setup for all correlations

First, set up whatever woodchuck dataset I am working with by reading in the ortholog table, choosing whether the orthologs to use are human, mouse, or woodchuck, and calculating the average expression for each cluster. The output of this section is the scaled cluster gene-expression matrix

groups <- "general_cell_labels"
# Read in ortholog table
geneNameTable <- read.table("~/Dropbox/Zoe/scf_version/make_gtf/orthofinder_sc2/homologene/collectedOrthofinderPairings.tsv",
                            sep = "\t",
                            header = TRUE)
woodchuckClusterAverages <- AverageExpression(sobj,
                                              assays = "SCT",
                                              slot = "scale.data",
                                              group.by = groups)
# Scale data
woodchuckClusterAverages$SCT <- na.omit(t(scale(t(as.matrix(woodchuckClusterAverages$SCT)))))
# Grab gene names from Seurat object
uniqueHier <- row.names(woodchuckClusterAverages$SCT)
uniqueHier <- as.data.frame(uniqueHier)
# Bind with geneNameTable to get correct order (notice uniqueHier is on left)
newNames <- dplyr::left_join(uniqueHier, geneNameTable, by = "uniqueHier")
# Get orthologs from either mouse or human
species <- "human"
if (species == "human") {
  # If human one-to-one ortho has NA, replace with mikado_final_sc2_stringent_noMito_protein column
  # This is to avoid and potential mistakes in recognizing things it shouldn't be recognizing
  newNames$speciesOneToOne <- ifelse(is.na(newNames$humanOneToOne), newNames$uniqueHier, newNames$humanOneToOne)
} else if (species == "mouse") {
  newNames$speciesOneToOne <- ifelse(is.na(newNames$mouseOneToOne), newNames$uniqueHier, newNames$mouseOneToOne)
} else if (species == "woodchuck") {
  newNames$speciesOneToOne <- newNames$uniqueHier
}
# Grab dataframe
woodchuckClusterAverages <- woodchuckClusterAverages$SCT
# Replace names with one-to-one orthologue of particular species
row.names(woodchuckClusterAverages) <- newNames$speciesOneToOne
# Make sure formatted correctly
woodchuckClusterAverages <- as.data.frame(woodchuckClusterAverages)
# Order by gene name
woodchuckClusterAverages <- woodchuckClusterAverages[order(row.names(woodchuckClusterAverages)),]
# Sanity check
head(woodchuckClusterAverages)

Dataset-specific setup

Correlation of woodchuck PBMCs with human 68k PBMC dataset from 10X Genomics

# Sanity check
head(allCellsMatrix)
       Activated CD8+ Naive CD8+ Memory and Reg T Naive CD4+          NK       CD8+          B
42430      -0.7290166 -1.4467216      -0.19073790 -0.4832807  0.02379348 -0.8928406 -0.2258430
42431      -0.2300094 -0.7300300      -0.26479348 -0.7995981 -0.18652940 -0.3474056 -0.6952459
42618      -0.1212209 -0.6309294      -0.09745206 -0.4354971 -0.36419075 -0.8527715 -0.3826776
A4GALT     -0.4058024 -1.0280327      -0.68648235 -0.4734361 -0.11159565 -0.5478332 -0.1352675
AATK       -1.0033368 -0.9033733      -0.11847519 -1.0810861 -0.10366579 -0.4257702 -0.2369504
ABCA1      -0.6939429 -1.0596759      -0.79368826 -0.8411861 -0.88868386 -0.1144697  0.6312458
       Megakaryocytes Monocytes and Dendritic B, Dendritic, T
42430        1.314882              1.50210970       1.1276549
42431        2.578802              0.03087083       0.6439395
42618        2.691420             -0.14763062       0.3409502
A4GALT       2.062829             -0.23671805       1.5623391
AATK         1.958543              1.15513309       0.7589817
ABCA1        1.186970              1.02547753       1.5479533

Correlation of woodchuck liver with human liver dataset from MacParland et al. (2018)

Correlation of woodchuck liver with human liver dataset from Aizarani et al.

allCellsMatrix <- allCellsMatrix[,as.character(sort(as.numeric(colnames(allCellsMatrix))))]
# Rename columns to be more meaningful (not totally confident I got all correct)
colnames(allCellsMatrix) <- c('NK, NKT and T cells (1)',
                              'Kupffer cells (2)',
                              'NK, NKT and T cells (3)',
                              'EPCAM+ cells and cholangiocytes (4)',
                              'NK, NKT and T cells (5)',
                              'Kupffer cells (6)',
                              'EPCAM+ cells and cholangiocytes (7)',
                              'B cells (8)',
                              'Liver sinusoidal endothelial cells (9)',
                              'Macrovascular endothelial cells (10)',
                              'Hepatocytes (11)',
                              'NK, NKT and T cells (12)',
                              'Liver sinusoidal endothelial cells (13)',
                              'Hepatocytes (14)',
                              'Other endothelial cells (15)',
                              'Other (16)',
                              'Hepatocytes (17)',
                              'NK, NKT and T cells (18)',
                              'NK, NKT and T cells (19)',
                              'Liver sinusoidal endothelial cells (20)',
                              'Macrovascular endothelial cells (21)',
                              'B cells (22)',
                              'Kupffer cells (23)',
                              'EPCAM+ cells and cholangiocytes (24)',
                              'Kupffer cells (25)',
                              'Other endothelial cells (26)',
                              'Other (27)',
                              'NK, NKT and T cells (28)',
                              'Macrovascular endothelial cells (29)',
                              'Hepatocytes (30)',
                              'Kupffer cells (31)',
                              'Macrovascular endothelial cells (32)',
                              'Stellate cells and myofibroblasts (33)',
                              'B cells (34)',
                              'Other endothelial cells (35)',
                              'Other (36)',
                              'Other (37)',
                              'B cells (38)',
                              'EPCAM+ cells and cholangiocytes (39)')
# Order by row name
allCellsMatrix <- allCellsMatrix[order(row.names(allCellsMatrix)),]
# Sanity check
head(allCellsMatrix)

speciesData <- "aizarani"

Correlation of woodchuck liver with woodchuck PBMCs. For this correlation, read in the woodchuck liver dataset at the beginning of this script and then read in the woodchuck PBMCs below

groups <- "general_cell_labels"
# Start with liver and read in woodchuck PBMCs again
load("~/Dropbox/Zoe/scf_version/analysis/healthy_sc/seurat_objects/no_dropletQC/integrated_PBMC_cca_kanchor5_scClustViz.RData")
Idents(scSeurat) <- "integrated_snn_res.0.6"
# Find cluster averages
pbmcClusterAverages <- AverageExpression(scSeurat,
                                         assays = "SCT",
                                         slot = "scale.data",
                                         group.by = groups)
pbmcClusterAverages <- as.data.frame(na.omit(t(scale(t(as.matrix(pbmcClusterAverages$SCT))))))
# Order by row name
allCellsMatrix <- pbmcClusterAverages[order(row.names(pbmcClusterAverages)),]
speciesData <- "PBMC"

Output plots for all correlations

# Now find intersecting genes
matches <- intersect(row.names(allCellsMatrix),
                     row.names(woodchuckClusterAverages))
# Look at how many genes matched
length(matches)
[1] 165
# Make new matrices with only matching gene names
toCor <- allCellsMatrix[matches,]
woodchuckAveragesCor <- woodchuckClusterAverages[matches,]
# Do Pearson
pearVal <- cor(toCor, woodchuckAveragesCor, method = "pearson")
heatmap(pearVal)
        #main = paste("Pearson correlation of", speciesData, "vs", woodchuckData),
        #xlab = woodchuckData,
        #ylab = speciesData)
        #margins = c(6,11))
#Rowv = NA,
#Colv = NA)
pdf(paste("./figures/", tissue, "/", tissue, "_", speciesData, "_PearsonCor.pdf", sep = ""),
    height = 13, width = 13)
heatmap(pearVal, margins = c(13,13))
dev.off()
png 
  2 

# Do Spearman
spearVal <- cor(toCor, woodchuckAveragesCor, method = "spearman")
heatmap(spearVal)
        #main = paste("Spearman correlation of", speciesData, "vs", woodchuckData),
        #xlab = woodchuckData,
        #ylab = speciesData)
        #margins = c(6,11))
#Rowv = NA,
#Colv = NA)
pdf(paste("./figures/", tissue, "/", tissue, "_", speciesData, "_SpearmanCor.pdf", sep = ""),
    height = 13, width = 13)
heatmap(spearVal, margins = c(13,13))
dev.off()
png 
  2 

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBzY3JpcHQgcmVhZHMgaW4gYm90aCBQQk1DIGFuZCBMaXZlciBTZXVyYXQgb2JqZWN0cywgYW5kIGdlbmVyYXRlcyBzZWxlY3QgZmlndXJlcyB1c2VkIGluIHRoZSBtYW51c2NyaXB0LgoKIyMgUHJlcGFyZSBvYmplY3RzCgpMb2FkIGxpYnJhcmllcwoKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KHNjQ2x1c3RWaXopCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShyY2FydG9jb2xvcikKbGlicmFyeShTZXVyYXRXcmFwcGVycykKYGBgCgpSZWFkIGluIGxpdmVyIG1hcAoKYGBge3J9CnNvYmogPC0gcmVhZFJEUygifi9Ecm9wYm94L1pvZS9zY2ZfdmVyc2lvbi9hbmFseXNpcy9oZWFsdGh5X3NjL3NldXJhdF9vYmplY3RzL2Ryb3BsZXRRQ19maWx0ZXJlZC9hbGxJbnRlZ3JhdGVkX2NjYV9rYW5jaG9yNV9ub0Jpb3BzeUhlcHNfZHJvcGxldFFDRmlsdGVyZWQuUkRTIikKcmVzIDwtICJpbnRlZ3JhdGVkX3Nubl9yZXMuMS40IgpJZGVudHMoc29iaikgPC0gcmVzCnRpc3N1ZSA8LSAibGl2ZXIiCmBgYAoKUmVhZCBpbiBQQk1DIG1hcAoKYGBge3J9CmxvYWQoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvaGVhbHRoeV9zYy9zZXVyYXRfb2JqZWN0cy9ub19kcm9wbGV0UUMvaW50ZWdyYXRlZF9QQk1DX2NjYV9rYW5jaG9yNV9zY0NsdXN0Vml6LlJEYXRhIikKc29iaiA8LSBzY1NldXJhdApyZXMgPC0gImludGVncmF0ZWRfc25uX3Jlcy4wLjYiCklkZW50cyhzb2JqKSA8LSByZXMKdGlzc3VlIDwtICJQQk1DIgpgYGAKCiMjIFZpc3VhbGl6YXRpb24gb2YgbWV0YWRhdGEKClVNQVAgd2l0aCBubyBjbHVzdGVyIG51bWJlcnMKCmBgYHtyfQpwbG90IDwtIERpbVBsb3Qoc29iaiwgbGFiZWwgPSBGQUxTRSkgJiBOb0xlZ2VuZCgpCnBsb3QKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl9VTUFQX2NsdXN0ZXJzX25vTGFiZWxzLnBkZiIsIHNlcCA9ICIiKSkKcGxvdApkZXYub2ZmKCkKYGBgCgpVTUFQIHdpdGggY2x1c3RlciBudW1iZXJzCgpgYGB7cn0KcGxvdCA8LSBEaW1QbG90KHNvYmosIGxhYmVsID0gVFJVRSkKcGxvdApwZGYocGFzdGUoIi4vZmlndXJlcy8iLCB0aXNzdWUsICIvIiwgdGlzc3VlLCAiX1VNQVBfY2x1c3RlcnNfbGFiZWxzLnBkZiIsIHNlcCA9ICIiKSkKcGxvdApkZXYub2ZmKCkKYGBgCgpNYXAgd2l0aCBTQ0lOQS1nZW5lcmF0ZWQgY2VsbC10eXBlIGxhYmVscwoKYGBge3J9CkRpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAic2NpbmFfbGFiZWxzX3JlZmluZWQiLCBsYWJlbCA9IFRSVUUpICYgTm9MZWdlbmQoKQpgYGAKCk1hcCB3aXRoIGdlbmVyYWwgY2VsbC10eXBlIGxhYmVscyBmb3IgcGFwZXIKCmBgYHtyfQpwbG90IDwtIERpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAiZ2VuZXJhbF9jZWxsX2xhYmVscyIsCiAgICAgICAgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUpICsKICBnZ3RpdGxlKE5VTEwpCnBsb3QKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl9VTUFQX2dlbmVyYWxfY2VsbF9sYWJlbHMucGRmIiwgc2VwID0gIiIpLAogICAgaGVpZ2h0ID0gOCwKICAgIHdpZHRoID0gMTIpCnBsb3QKZGV2Lm9mZigpCmBgYAoKTWFwIGdyb3VwaW5nIGJ5IGdlbmVyYWwgY2VsbCB0eXBlIGxhYmVscyBidXQgd2l0aCBubyBsYWJlbHMgb24gcGxvdAoKYGBge3J9CnBsb3QgPC0gRGltUGxvdChzb2JqLCBncm91cC5ieSA9ICJnZW5lcmFsX2NlbGxfbGFiZWxzIikgKwogIGdndGl0bGUoTlVMTCkgJgogIE5vTGVnZW5kKCkKcGxvdApwZGYocGFzdGUoIi4vZmlndXJlcy8iLCB0aXNzdWUsICIvIiwgdGlzc3VlLCAiX1VNQVBfZ2VuZXJhbF9jZWxsX2xhYmVsc19ub0xhYmVscy5wZGYiLCAKICAgICAgICAgIHNlcCA9ICIiKSkKcGxvdApkZXYub2ZmKCkKYGBgCgpNYXAgd2l0aCBvcmlnaW5hbCBpZGVudGl0aWVzCgpgYGB7cn0KcGxvdCA8LSBEaW1QbG90KHNvYmosIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiLAogICAgICAgIGNvbHMgPSBjYXJ0b19wYWwobGVuZ3RoKGxldmVscyhhcy5mYWN0b3Ioc29iaiRvcmlnLmlkZW50KSkpLCAiU2FmZSIpKSArCiAgZ2d0aXRsZShOVUxMKQpwbG90CnBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfVU1BUF9vcmlnX2lkZW50cy5wZGYiLCAKICAgICAgICAgIHNlcCA9ICIiKSkKcGxvdApkZXYub2ZmKCkKYGBgCgpCYXJwbG90IHdpdGggb3JpZ2luYWwgaWRlbnRpdGllcyBvbiBhIGNsdXN0ZXItbGV2ZWwgZ3JvdXBpbmc6CgpgYGB7cn0KIyBNZXRhIGRhdGEgdG8gcGxvdDoKZGYgPC0gc29iakBtZXRhLmRhdGEKIyBDaGVjayB3aGF0IGNvbHVtbiB0aGUgY2x1c3RlciBpZGVudGl0aWVzIGFyZSBpbgpjb2wgPC0gd2hpY2goY29sbmFtZXMoZGYpID09IHJlcykKIyBPcmRlciBjbHVzdGVycwpkZlssY29sXSA8LSBmYWN0b3IoSWRlbnRzKHNvYmopLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoc29ydChhcy5udW1lcmljKGxldmVscyhJZGVudHMoc29iaikpKSkpKQojIEJhc2ljIHBsb3Qgb2YgY2x1c3RlcnMgYnkgcmVwbGljYXRlCmdncGxvdChkZiwgYWVzKHggPSBnZXQocmVzKSwgZmlsbCA9IG9yaWcuaWRlbnQpKSArCiAgZ2VvbV9iYXIoKSArCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSkKIyBQbG90IGFzIHByb3BvcnRpb24gb3IgcGVyY2VudGFnZSBvZiBjbHVzdGVyCmdncGxvdChkZiwgYWVzKHggPSBnZXQocmVzKSwgZmlsbCA9IG9yaWcuaWRlbnQpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQpgYGAKCkJhcnBsb3Qgd2l0aCBvcmlnaW5hbCBpZGVudGl0aWVzIG9uIGEgZ3JvdXBlZCBieSBnZW5lcmFsIGNlbGwgbGFiZWxzOgoKYGBge3J9CmRmIDwtIHNvYmpAbWV0YS5kYXRhCnBsb3QxIDwtIGdncGxvdChkZiwgYWVzKHggPSBnZW5lcmFsX2NlbGxfbGFiZWxzLCBmaWxsID0gb3JpZy5pZGVudCkpICsKICBnZW9tX2JhcigpICsKICBzY2FsZV9maWxsX2NhcnRvX2QobmFtZSA9IE5VTEwsIHBhbGV0dGUgPSAiU2FmZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB5bGFiKCJOdW1iZXIgb2YgY2VsbHMiKQpwbG90MQpwZGYocGFzdGUoIi4vZmlndXJlcy8iLCB0aXNzdWUsICIvIiwgdGlzc3VlLCAiX2JhcnBsb3Rfb3JpZ19pZGVudF9jb3VudHMucGRmIiwgCiAgICAgICAgICBzZXAgPSAiIikpCnBsb3QxCmRldi5vZmYoKQojIFBsb3QgYXMgcHJvcG9ydGlvbiBvciBwZXJjZW50YWdlIG9mIGNsdXN0ZXIKcGxvdDIgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IGdlbmVyYWxfY2VsbF9sYWJlbHMsIGZpbGwgPSBvcmlnLmlkZW50KSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArCiAgc2NhbGVfZmlsbF9jYXJ0b19kKG5hbWUgPSBOVUxMLCBwYWxldHRlID0gIlNhZmUiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgeWxhYigiUHJvcG9ydGlvbiBvZiBjZWxscyIpCnBsb3QyCnBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfYmFycGxvdF9vcmlnX2lkZW50X3Byb3BvcnRpb25zLnBkZiIsIAogICAgICAgICAgc2VwID0gIiIpKQpwbG90MgpkZXYub2ZmKCkKYGBgCgojIyBEb3RwbG90cwoKR2VuZXJhdGUgZG90cGxvdCB3aXRoIHNwZWNpZmljIG1hcmtlcnMKCmBgYHtyfQpEb3RQbG90KHNvYmosCiAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICBmZWF0dXJlcyA9IGMoIlBUUFJDIiwgIkNBTENSTCIsICJOS0c3IiwgIkNEM0UiLCAiTUFSQ08iLCAiTFlaLTEiLCAiQ0QxOSIsICJNUzRBMSIsICJTVEFCMiIpCiAgICAgICAgKSArCiAgZ2d0aXRsZSgiU2VsZWN0IGZlYXR1cmVzIGZvciBsaXZlciBtYXAiKQpgYGAKCiMjIEhlYXRtYXBzCgpDYWxjdWxhdGUgbWFya2VycyBmb3IgZ2VuZXJhbCBjZWxsIGxhYmVscyB0aGVuIHJlc2V0IHJlc29sdXRpb24KCmBgYHtyfQpJZGVudHMoc29iaikgPC0gImdlbmVyYWxfY2VsbF9sYWJlbHMiCnNvYmpfbWFya2VycyA8LSBSdW5QcmVzdG9BbGwoc29iaiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4ucGN0ID0gMC4yNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMC4yNSkKc29ial9tYXJrZXJzICU+JQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgICBzbGljZV9tYXgobiA9IDIsIG9yZGVyX2J5ID0gYXZnX2xvZzJGQykKSWRlbnRzKHNvYmopIDwtIHJlcwpgYGAKClNhdmUgbWFya2VycwoKYGBge3J9Cmdyb3VwcyA9ICJnZW5lcmFsX2NlbGxfbGFiZWxzIgp3cml0ZS50YWJsZShzb2JqX21hcmtlcnMsCiAgICAgICAgICAgIGZpbGUgPSBwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLAogICAgICAgICAgICAgICAgICAgICAgICAgdGlzc3VlLCAiX21hcmtlcnNfIiwgZ3JvdXBzLCAiLnRzdiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIpLAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLAogICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgY29sLm5hbWVzID0gVFJVRSkKYGBgCgpHZW5lcmF0ZSBoZWF0bWFwIHdpdGggdG9wIDUgbWFya2VycyBncm91cGluZyBieSBnZW5lcmFsIGNlbGwgdHlwZXMKCmBgYHtyfQojIFJlbW92ZSBtaWthZG8gZ2VuZXMgZnJvbSBtYXJrZXIgbGlzdApzb2JqX21hcmtlcnMgPC0gc29ial9tYXJrZXJzW2dyZXAoIm1pa2FkbyIsIHJvd25hbWVzKHNvYmpfbWFya2VycyksIGludmVydCA9IFRSVUUpLF0Kc29ial9tYXJrZXJzICU+JQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgICB0b3BfbihuID0gNSwgd3QgPSBhdmdfbG9nMkZDKSAtPiB0b3AKIyBJZiBsaXZlciwgc2VsZWN0IGZld2VyIGNlbGxzCmlmICh0aXNzdWUgPT0gImxpdmVyIikgewogIGNlbGxzIDwtIHNhbXBsZShjb2xuYW1lcyhzb2JqKSwgc2l6ZSA9IDMwMDAwKQp9IGVsc2UgaWYgKHRpc3N1ZSA9PSAiUEJNQyIpIHsKICBjZWxscyA8LSBjb2xuYW1lcyhzb2JqKQp9CkRvSGVhdG1hcChzb2JqLCBmZWF0dXJlcyA9IHRvcCRnZW5lLCBncm91cC5ieSA9ICJnZW5lcmFsX2NlbGxfbGFiZWxzIiwgc2l6ZSA9IDMsIAogICAgICAgICAgYW5nbGUgPSA5MCwgY2VsbHMgPSBjZWxscykgKwogIE5vTGVnZW5kKCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQpgYGAKCk1ha2UgUERGIG9mIGhlYXRtYXAKCmBgYHtyfQpncm91cHMgPC0gImdlbmVyYWxfY2VsbF9sYWJlbHMiCnBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfaGVhdG1hcF8iLCBncm91cHMsICIucGRmIiwgc2VwID0gIiIpLAogICAgaGVpZ2h0ID0gMTEsCiAgICB3aWR0aCA9IDcpCkRvSGVhdG1hcChzb2JqLCBmZWF0dXJlcyA9IHRvcCRnZW5lLCBncm91cC5ieSA9ICJnZW5lcmFsX2NlbGxfbGFiZWxzIiwgc2l6ZSA9IDIsIAogICAgICAgICAgYW5nbGUgPSA5MCwgY2VsbHMgPSBjZWxscykgKwogIE5vTGVnZW5kKCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQpkZXYub2ZmKCkKYGBgCgoKIyMgRmVhdHVyZSBwbG90cwoKTWFrZSBzcGVjaWZpYyBwbG90cyB3aXRoIHNwZWNpZmljIGdlbmVzLiBUaGUgZ2VuZXMgd2UgYXJlIGludGVyZXN0ZWQgaW4gaW5jbHVkZTogKlBUUFJDLCBDQUxDUkwsIE5LRzcsIENEM0UsIE1BUkNPLCBMWVosIENEMTksIE1TNEExLCBTVEFCMiwgQUxCLCBDRDQsIENEOEEsIENMRUM0RywgQ0Q1TCwgQzFRQiwgQUNUQTIsIFZXRiwgSUdMTDUsIENENjgqLiBDYW4gYWxzbyBwbG90IGluIGl0YWxpY3MuCgpgYGB7cn0KZ2VuZUNvZGUgPC0gInNjdF9MWVotMSIgIyBXb29kY2h1Y2stc3BlY2lmaWMgbm9tZW5jbGF0dXJlIGZvciB0aGlzIGdlbm9tZQpnZW5lIDwtICJMWVoiCm1hcFR5cGUgPC0gIkxpdmVyIgpGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9IGdlbmVDb2RlKSArCiAgZ2d0aXRsZShwYXN0ZShnZW5lLCAiLSIsIG1hcFR5cGUsICJtYXAiKSkKRmVhdHVyZVBsb3Qoc29iaiwgZmVhdHVyZXMgPSBnZW5lQ29kZSkgKwogIGdndGl0bGUoYnF1b3RlKH5pdGFsaWMoLihnZW5lKSkpKQpgYGAKCkFub3RoZXIgdmVyc2lvbiBvZiB0aGUgZmVhdHVyZSBwbG90IHRoYXQgb3V0cHV0cyBnZW5lcyBpbiBpdGFsaWNzCgpgYGB7cn0KaWYgKHRpc3N1ZSA9PSAiUEJNQyIpIHsKIGdlbmVDb2RlcyA8LSBjKCJzY3RfUFRQUkMiLCJzY3RfTktHNyIsInNjdF9DRDE0IiwKICAgICAgICAgICAgICAgInNjdF9DRDNFIiwic2N0X01BUkNPIiwic2N0X0xZWi0xIiwKICAgICAgICAgICAgICAgInNjdF9DRDE5Iiwic2N0X01TNEExIiwic2N0X1NUQUIyIiwKICAgICAgICAgICAgICAgInNjdF9DRDQiLCJzY3RfQ0Q4QSIsICJzY3RfWENMMTtYQ0wyIiwKICAgICAgICAgICAgICAgInNjdF9DRDVMIiwic2N0X0MxUUIiLCAic2N0X0xFRjEiLAogICAgICAgICAgICAgICAic2N0X0FDVEEyIiwic2N0X1ZXRiIsInNjdF9JR0xMNS0xIiwKICAgICAgICAgICAgICAgInNjdF9DRDY4Iiwic2N0X0ZDR1IzQTtGQ0dSM0IiLCJzY3RfVE9QMkEiKQogZ2VuZXMgPC0gYygiUFRQUkMiLCJOS0c3IiwiQ0QxNCIsIkNEM0UiLCJNQVJDTyIsIkxZWiIsCiAgICAgICAgICAgIkNEMTkiLCJNUzRBMSIsIlNUQUIyIiwiQ0Q0IiwiQ0Q4QSIsICJYQ0wxO1hDTDIiLAogICAgICAgICAgICJDRDVMIiwiQzFRQiIsIkxFRjEiLCJBQ1RBMiIsIlZXRiIsIklHTEw1IiwiQ0Q2OCIsCiAgICAgICAgICAgIkZDR1IzQTtGQ0dSM0IiLCJUT1AyQSIpIAp9IGVsc2UgaWYgKHRpc3N1ZSA9PSAibGl2ZXIiKSB7CiAgZ2VuZUNvZGVzIDwtIGMoInNjdF9QdHByYyIsInNjdF9DQUxDUkwiLCJzY3RfTktHNyIsCiAgICAgICAgICAgICAgICAgInNjdF9DRDNFIiwic2N0X01BUkNPIiwic2N0X0xZWi0xIiwKICAgICAgICAgICAgICAgICAic2N0X0NEMTkiLCJzY3RfTVM0QTEiLCJzY3RfU1RBQjIiLAogICAgICAgICAgICAgICAgICJzY3RfQUxCLTEiLCJzY3RfQ0Q0Iiwic2N0X0NEOEEiLAogICAgICAgICAgICAgICAgICJzY3RfQ0xFQzRHIiwic2N0X0NENUwiLCJzY3RfQzFRQiIsCiAgICAgICAgICAgICAgICAgInNjdF9BQ1RBMiIsInNjdF9WV0YiLCJzY3RfSUdMTDUtMSIsCiAgICAgICAgICAgICAgICAgInNjdF9DRDY4Iiwic2N0X1hDTDE7WENMMiIsInNjdF9MRUYxIiwKICAgICAgICAgICAgICAgICAic2N0X1JTUE8zIiwic2N0X01FQ09NIikKICBnZW5lcyA8LSBjKCJQVFBSQyIsIkNBTENSTCIsIk5LRzciLCJDRDNFIiwiTUFSQ08iLCJMWVoiLAogICAgICAgICAgICAgIkNEMTkiLCJNUzRBMSIsIlNUQUIyIiwiQUxCIiwiQ0Q0IiwiQ0Q4QSIsCiAgICAgICAgICAgICAiQ0xFQzRHIiwiQ0Q1TCIsIkMxUUIiLCJBQ1RBMiIsIlZXRiIsIklHTEw1IiwiQ0Q2OCIsCiAgICAgICAgICAgICAiWENMMTtYQ0wyIiwiTEVGMSIsIlJTUE8zIiwiTUVDT00iKSAKfQpmb3IobnVtIGluIDI6bGVuZ3RoKGdlbmVDb2RlcykpIHsKICBwbG90IDwtIEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGdlbmVDb2Rlc1tudW1dKSArCiAgICBnZ3RpdGxlKGJxdW90ZSh+aXRhbGljKC4oZ2VuZXNbbnVtXSkpKSkKICBwcmludChwbG90KQogIHBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfIiwgZ2VuZXNbbnVtXSwgIl9VTUFQLnBkZiIsIHNlcCA9ICIiKSkKICBwcmludChwbG90KQogIGRldi5vZmYoKQp9CmBgYAoKIyMjIENlbGwtcG9wdWxhdGlvbi1zcGVjaWZpYyBtYXJrZXJzCgpQbG90IG1hcmtlciBnZW5lcyBmb3Igc3BlY2lmaWMgY2VsbCBwb3B1bGF0aW9ucwoKRW5kb3RoZWxpYWwgY2VsbHM6CgpgYGB7cn0KZ2VuZUNvZGVzIDwtIGMoInNjdF9TVEFCMiIsInNjdF9JVEdBMSIsInNjdF9DRDU1Iiwic2N0X0xZVkUxIiwKICAgICAgICAgICAgICAgInNjdF9DRDM0Iiwic2N0X1ZXRiIsInNjdF9JRklUTTM7SUZJVE0yO0lGSVRNMSIsInNjdF9SU1BPMyIsCiAgICAgICAgICAgICAgICJzY3RfTUVDT00iLCJzY3RfTWVjb20iLCJzY3RfQ0FMQ1JMIiwic2N0X0xPQzExNDA4OTY1NCIsCiAgICAgICAgICAgICAgICJzY3RfUkFNUDIiLCJzY3RfQlNUMiIsInNjdF9DTEVDNEciLCJzY3RfQ1RTVjtDVFNMIiwKICAgICAgICAgICAgICAgInNjdF9TVEFCMSIsInNjdF9QTEFDOSIsInNjdF9QRUNBTTEiLCJzY3RfV05UMiIsCiAgICAgICAgICAgICAgICJzY3RfTVlMNiIsInNjdF9OUjJGMiIpCmdlbmVzIDwtIGMoIlNUQUIyIiwiSVRHQTEiLCJDRDU1IiwiTFlWRTEiLAogICAgICAgICAgICJDRDM0IiwiVldGIiwiSUZJVE0zIiwiUlNQTzMiLAogICAgICAgICAgICJNRUNPTSIsIk1lY29tIiwiQ0FMQ1JMIiwiTE9DMTE0MDg5NjU0IiwKICAgICAgICAgICAiUkFNUDIiLCJCU1QyIiwiQ0xFQzRHIiwiQ1RTVjtDVFNMIiwKICAgICAgICAgICAiU1RBQjEiLCJQTEFDOSIsIlBFQ0FNMSIsIldOVDIiLAogICAgICAgICAgICJNWUw2IiwiTlIyRjIiKSAKZm9yKG51bSBpbiAxOmxlbmd0aChnZW5lQ29kZXMpKSB7CiAgcGxvdCA8LSBGZWF0dXJlUGxvdChzb2JqLAogICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBnZW5lQ29kZXNbbnVtXSkgKwogICAgZ2d0aXRsZShicXVvdGUofml0YWxpYyguKGdlbmVzW251bV0pKSkpCiAgcHJpbnQocGxvdCkKICBwZGYocGFzdGUoIi4vZmlndXJlcy8iLCB0aXNzdWUsICIvIiwgdGlzc3VlLCAiXyIsIGdlbmVzW251bV0sICJfVU1BUC5wZGYiLCBzZXAgPSAiIikpCiAgcHJpbnQocGxvdCkKICBkZXYub2ZmKCkKfQpgYGAKCkx5bXBob2N5dGVzOgoKYGBge3J9CmdlbmVDb2RlcyA8LSBjKCJzY3RfQ0QzRCIsInNjdF9DRDNFIiwic2N0X0NEOEEiLCJzY3RfTktHNyIsCiAgICAgICAgICAgICAgICJzY3RfS0xSRDEiLCJzY3RfS0xSQjEiLCJzY3RfR1pNQSIsInNjdF9MRUYxIiwKICAgICAgICAgICAgICAgInNjdF9JTDdSLTEiLCJzY3RfRU9NRVMiLCJzY3RfVElHSVQiLCJzY3RfWENMMTtYQ0wyIiwKICAgICAgICAgICAgICAgInNjdF9UT1giLCJzY3RfQ1RMQTQiLCJzY3RfQ0Q0Iiwic2N0X0daTUsiKQpnZW5lcyA8LSBjKCJDRDNEIiwiQ0QzRSIsIkNEOEEiLCJOS0c3IiwKICAgICAgICAgICAiS0xSRDEiLCJLTFJCMSIsIkdaTUEiLCJMRUYxIiwKICAgICAgICAgICAiSUw3UiIsIkVPTUVTIiwiVElHSVQiLCJYQ0wxO1hDTDIiLAogICAgICAgICAgICJUT1giLCJDVExBNCIsIkNENCIsIkdaTUsiKSAKZm9yKG51bSBpbiAxOmxlbmd0aChnZW5lQ29kZXMpKSB7CiAgcGxvdCA8LSBGZWF0dXJlUGxvdChzb2JqLAogICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBnZW5lQ29kZXNbbnVtXSkgKwogICAgZ2d0aXRsZShicXVvdGUofml0YWxpYyguKGdlbmVzW251bV0pKSkpCiAgcHJpbnQocGxvdCkKICBwZGYocGFzdGUoIi4vZmlndXJlcy8iLCB0aXNzdWUsICIvIiwgdGlzc3VlLCAiXyIsIGdlbmVzW251bV0sICJfVU1BUC5wZGYiLCBzZXAgPSAiIikpCiAgcHJpbnQocGxvdCkKICBkZXYub2ZmKCkKfQpgYGAKCk1lc2VuY2h5bWU6CgpgYGB7cn0KZ2VuZUNvZGVzIDwtIGMoInNjdF9ISElQIiwic2N0X0NPTDFBMiIsInNjdF9DT0wzQTEiLCJzY3RfSUdGQlA3IiwKICAgICAgICAgICAgICAgInNjdF9JR0ZCUDMiLCJzY3RfRENOIiwic2N0X0NPTDFBMSIsInNjdF9TUEFSQyIsCiAgICAgICAgICAgICAgICJzY3RfUkJQMSIsICJzY3RfQ0FMQ1JMIikKZ2VuZXMgPC0gYygiSEhJUCIsIkNPTDFBMiIsIkNPTDNBMSIsIklHRkJQNyIsCiAgICAgICAgICAgIklHRkJQMyIsIkRDTiIsIkNPTDFBMSIsIlNQQVJDIiwKICAgICAgICAgICAiUkJQMSIsIkNBTENSTCIpIApmb3IobnVtIGluIDE6bGVuZ3RoKGdlbmVDb2RlcykpIHsKICBwbG90IDwtIEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGdlbmVDb2Rlc1tudW1dKSArCiAgICBnZ3RpdGxlKGJxdW90ZSh+aXRhbGljKC4oZ2VuZXNbbnVtXSkpKSkKICBwcmludChwbG90KQogIHBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfIiwgZ2VuZXNbbnVtXSwgIl9VTUFQLnBkZiIsIHNlcCA9ICIiKSkKICBwcmludChwbG90KQogIGRldi5vZmYoKQp9CmBgYAoKQ2hvbGFuZ2lvY3l0ZXM6CgpgYGB7cn0KZ2VuZUNvZGVzIDwtIGMoInNjdF9LUlQxOSIsInNjdF9DRlRSIiwic2N0X0VQQ0FNIiwic2N0X1NMQzRBNCIpCmdlbmVzIDwtIGMoIktSVDE5IiwiQ0ZUUiIsIkVQQ0FNIiwiU0xDNEE0IikgCmZvcihudW0gaW4gMTpsZW5ndGgoZ2VuZUNvZGVzKSkgewogIHBsb3QgPC0gRmVhdHVyZVBsb3Qoc29iaiwKICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZUNvZGVzW251bV0pICsKICAgIGdndGl0bGUoYnF1b3RlKH5pdGFsaWMoLihnZW5lc1tudW1dKSkpKQogIHByaW50KHBsb3QpCiAgcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl8iLCBnZW5lc1tudW1dLCAiX1VNQVAucGRmIiwgc2VwID0gIiIpKQogIHByaW50KHBsb3QpCiAgZGV2Lm9mZigpCn0KYGBgCgpMb29rIGF0IHpvbmF0aW9uIGdlbmUgc2lnbmF0dXJlczoKCmBgYHtyfQpjdl9nZW5lcyA8LSBjKCJGRVRVQiIsIkhNR0NTMSIsIkNZUDJFMSIsIkdMVUQxO0dMVUQyIiwiQ1lQMUEyIiwKICAgICAgICAgICAgICAiUkdOIiwiSU5NVCIsIkNPTVQiLCJGRFBTIiwiU1BSLTEiKQpjdl9nZW5lcwpwcF9nZW5lcyA8LSBjKCJTYWEyO1NhYTEtMSIsIkhBTVAiLCJBUE9BMSIsIkFQT0MyIiwiQ1JZTDEiLAogICAgICAgICAgICAgICJBTVkxQTtBTVkxQztBTVkxQjtBTVkyQTtBTVkyQiIsIk1ULUFUUDYiLCJVUk9DMSIsCiAgICAgICAgICAgICAgIkFQT0EyIiwiTVQtQ08zIikKcHBfZ2VuZXMKYGBgCgoKIyMgQ29ycmVsYXRpb24gcGxvdHMKCkdlbmVyYXRlIGhlYXRtYXBzIGNvbXBhcmluZyB3b29kY2h1Y2sgY2x1c3RlcnMgd2l0aCB2YXJpb3VzIGRhdGFzZXRzCgojIyMgU2V0dXAgZm9yIGFsbCBjb3JyZWxhdGlvbnMKCkZpcnN0LCBzZXQgdXAgd2hhdGV2ZXIgd29vZGNodWNrIGRhdGFzZXQgSSBhbSB3b3JraW5nIHdpdGggYnkgcmVhZGluZyBpbiB0aGUgb3J0aG9sb2cgdGFibGUsIGNob29zaW5nIHdoZXRoZXIgdGhlIG9ydGhvbG9ncyB0byB1c2UgYXJlIGh1bWFuLCBtb3VzZSwgb3Igd29vZGNodWNrLCBhbmQgY2FsY3VsYXRpbmcgdGhlIGF2ZXJhZ2UgZXhwcmVzc2lvbiBmb3IgZWFjaCBjbHVzdGVyLiBUaGUgb3V0cHV0IG9mIHRoaXMgc2VjdGlvbiBpcyB0aGUgc2NhbGVkIGNsdXN0ZXIgZ2VuZS1leHByZXNzaW9uIG1hdHJpeAoKYGBge3J9Cmdyb3VwcyA8LSAiZ2VuZXJhbF9jZWxsX2xhYmVscyIKIyBSZWFkIGluIG9ydGhvbG9nIHRhYmxlCmdlbmVOYW1lVGFibGUgPC0gcmVhZC50YWJsZSgifi9Ecm9wYm94L1pvZS9zY2ZfdmVyc2lvbi9tYWtlX2d0Zi9vcnRob2ZpbmRlcl9zYzIvaG9tb2xvZ2VuZS9jb2xsZWN0ZWRPcnRob2ZpbmRlclBhaXJpbmdzLnRzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSkKd29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheXMgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QgPSAic2NhbGUuZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9IGdyb3VwcykKIyBTY2FsZSBkYXRhCndvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyRTQ1QgPC0gbmEub21pdCh0KHNjYWxlKHQoYXMubWF0cml4KHdvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyRTQ1QpKSkpKQojIEdyYWIgZ2VuZSBuYW1lcyBmcm9tIFNldXJhdCBvYmplY3QKdW5pcXVlSGllciA8LSByb3cubmFtZXMod29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzJFNDVCkKdW5pcXVlSGllciA8LSBhcy5kYXRhLmZyYW1lKHVuaXF1ZUhpZXIpCiMgQmluZCB3aXRoIGdlbmVOYW1lVGFibGUgdG8gZ2V0IGNvcnJlY3Qgb3JkZXIgKG5vdGljZSB1bmlxdWVIaWVyIGlzIG9uIGxlZnQpCm5ld05hbWVzIDwtIGRwbHlyOjpsZWZ0X2pvaW4odW5pcXVlSGllciwgZ2VuZU5hbWVUYWJsZSwgYnkgPSAidW5pcXVlSGllciIpCiMgR2V0IG9ydGhvbG9ncyBmcm9tIGVpdGhlciBtb3VzZSBvciBodW1hbgpzcGVjaWVzIDwtICJodW1hbiIKaWYgKHNwZWNpZXMgPT0gImh1bWFuIikgewogICMgSWYgaHVtYW4gb25lLXRvLW9uZSBvcnRobyBoYXMgTkEsIHJlcGxhY2Ugd2l0aCBtaWthZG9fZmluYWxfc2MyX3N0cmluZ2VudF9ub01pdG9fcHJvdGVpbiBjb2x1bW4KICAjIFRoaXMgaXMgdG8gYXZvaWQgYW5kIHBvdGVudGlhbCBtaXN0YWtlcyBpbiByZWNvZ25pemluZyB0aGluZ3MgaXQgc2hvdWxkbid0IGJlIHJlY29nbml6aW5nCiAgbmV3TmFtZXMkc3BlY2llc09uZVRvT25lIDwtIGlmZWxzZShpcy5uYShuZXdOYW1lcyRodW1hbk9uZVRvT25lKSwgbmV3TmFtZXMkdW5pcXVlSGllciwgbmV3TmFtZXMkaHVtYW5PbmVUb09uZSkKfSBlbHNlIGlmIChzcGVjaWVzID09ICJtb3VzZSIpIHsKICBuZXdOYW1lcyRzcGVjaWVzT25lVG9PbmUgPC0gaWZlbHNlKGlzLm5hKG5ld05hbWVzJG1vdXNlT25lVG9PbmUpLCBuZXdOYW1lcyR1bmlxdWVIaWVyLCBuZXdOYW1lcyRtb3VzZU9uZVRvT25lKQp9IGVsc2UgaWYgKHNwZWNpZXMgPT0gIndvb2RjaHVjayIpIHsKICBuZXdOYW1lcyRzcGVjaWVzT25lVG9PbmUgPC0gbmV3TmFtZXMkdW5pcXVlSGllcgp9CiMgR3JhYiBkYXRhZnJhbWUKd29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzIDwtIHdvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyRTQ1QKIyBSZXBsYWNlIG5hbWVzIHdpdGggb25lLXRvLW9uZSBvcnRob2xvZ3VlIG9mIHBhcnRpY3VsYXIgc3BlY2llcwpyb3cubmFtZXMod29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzKSA8LSBuZXdOYW1lcyRzcGVjaWVzT25lVG9PbmUKIyBNYWtlIHN1cmUgZm9ybWF0dGVkIGNvcnJlY3RseQp3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMgPC0gYXMuZGF0YS5mcmFtZSh3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMpCiMgT3JkZXIgYnkgZ2VuZSBuYW1lCndvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyA8LSB3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXNbb3JkZXIocm93Lm5hbWVzKHdvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcykpLF0KIyBTYW5pdHkgY2hlY2sKaGVhZCh3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMpCmBgYAoKIyMjIERhdGFzZXQtc3BlY2lmaWMgc2V0dXAKCkNvcnJlbGF0aW9uIG9mIHdvb2RjaHVjayBQQk1DcyB3aXRoIGh1bWFuIDY4ayBQQk1DIGRhdGFzZXQgZnJvbSAxMFggR2Vub21pY3MKCmBgYHtyfQojIE5vdyBuZWVkIHRvIHJlYWQgaW4gNjhLIFBCTUMgZGF0YQpodW1hblBCTUMgPC0gcmVhZC5jc3YoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvY29ycmVsYXRpb25UZXN0cy82OEtfcGJtY19kYXRhLzY4S19lbnJpY2hlZEdlbmVzLmNzdiIsCiAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBGQUxTRSkKIyBHZXQgcmlkIG9mIHRvcCByb3cKaHVtYW5QQk1DIDwtIGh1bWFuUEJNQ1stMSxdCiMgU2VwYXJhdGUgYWxsIGNlbGwgYW5kIG15bG9pZCBjZWxsIGRhdGEKYWxsQ2VsbHMgPC0gc2VsZWN0KGh1bWFuUEJNQywgVjEsIFYyLCBWMykKbXllbG9pZCA8LSBzZWxlY3QoaHVtYW5QQk1DLCBWNSwgVjYsIFY3KQojIFJlbmFtZSBhbmQgZ2V0IHJpZCBvZiBmaXJzdCByb3cKY29sbmFtZXMoYWxsQ2VsbHMpIDwtIGMoIkNsdXN0ZXIiLCAiR2VuZSIsICJFbnJpY2htZW50IikKY29sbmFtZXMobXllbG9pZCkgPC0gYygiQ2x1c3RlciIsICJHZW5lIiwgIkVucmljaG1lbnQiKQojIEdldCByaWQgb2YgdG9wIHJvdwphbGxDZWxscyA8LSBhbGxDZWxsc1stMSxdCm15ZWxvaWQgPC0gbXllbG9pZFstMSxdCiMgSSBjYW4gdGhlbiBmaWx0ZXIgdGhlIHJvd3MgYW5kIGJpbmQgdGhlIGRhdGEgZnJhbWVzIGJhY2sgdG9nZXRoZXIgYnkgZ2VuZSBuYW1lCmZvciAoaiBpbiAxOjEwKSB7CiAgZGF0IDwtIGRwbHlyOjpmaWx0ZXIoYWxsQ2VsbHMsIENsdXN0ZXIgPT0gaikKICAjZGF0IDwtIGdldChwYXN0ZSgiYWxsQ2VsbHMiLCBqLCBzZXAgPSAiIikpCiAgIyBNdWx0aXBseSBlbnJpY2htZW50IHZhbHVlcyBieSAtMSBiZWNhdXNlIHRoZSBzaWducyBhcmUgYmFja3dhcmRzPz8/CiAgZGF0JEVucmljaG1lbnQgPC0gYXMubnVtZXJpYyhkYXQkRW5yaWNobWVudCkgKiAtMQogIGRhdCA8LSBkcGx5cjo6c2VsZWN0KGRhdCwgR2VuZSwgRW5yaWNobWVudCkKICBjb2xuYW1lcyhkYXQpIDwtIGMoIkdlbmUiLCBwYXN0ZSgiRW5yaWNobWVudCIsIGosIHNlcCA9ICIiKSkKICBpZiAoaiA9PSAxKSB7CiAgICBhbGxDZWxsc01hdHJpeCA8LSBkYXQKICB9CiAgZWxzZSB7CiAgICBhbGxDZWxsc01hdHJpeCA8LSBkcGx5cjo6ZnVsbF9qb2luKGFsbENlbGxzTWF0cml4LCBkYXQsIGJ5ID0gIkdlbmUiKQogIH0KfQojIE1ha2Ugcm93IG5hbWVzIGdlbmUgbmFtZXMKcm93bmFtZXMoYWxsQ2VsbHNNYXRyaXgpIDwtIGFsbENlbGxzTWF0cml4JEdlbmUKYWxsQ2VsbHNNYXRyaXggPC0gZHBseXI6OnNlbGVjdChhbGxDZWxsc01hdHJpeCwgLUdlbmUpCiMgTWFrZSBjb2x1bW4gbmFtZXMgY2VsbCB0eXBlcwpjb2xuYW1lcyhhbGxDZWxsc01hdHJpeCkgPC0gYygiQWN0aXZhdGVkIENEOCsiLCAiTmFpdmUgQ0Q4KyIsICJNZW1vcnkgYW5kIFJlZyBUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5haXZlIENENCsiLCAiTksiLCAiQ0Q4KyIsICJCIiwgIk1lZ2FrYXJ5b2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1vbm9jeXRlcyBhbmQgRGVuZHJpdGljIiwgIkIsIERlbmRyaXRpYywgVCIpCiMgU2NhbGUgYWNyb3NzIGNvbHVtbnMKYWxsQ2VsbHNNYXRyaXggPC0gdChzY2FsZSh0KGFsbENlbGxzTWF0cml4KSkpCiMgT3JkZXIgZ2VuZXMgYWxwaGFiZXRpY2FsbHkgYnkgZ2VuZSBuYW1lCmFsbENlbGxzTWF0cml4IDwtIGFsbENlbGxzTWF0cml4W29yZGVyKHJvdy5uYW1lcyhhbGxDZWxsc01hdHJpeCkpLF0KIyBTYW5pdHkgY2hlY2sKaGVhZChhbGxDZWxsc01hdHJpeCkKc3BlY2llc0RhdGEgPC0gIjY4S1BCTUMiCmBgYAoKQ29ycmVsYXRpb24gb2Ygd29vZGNodWNrIGxpdmVyIHdpdGggaHVtYW4gbGl2ZXIgZGF0YXNldCBmcm9tIE1hY1BhcmxhbmQgKmV0IGFsLiogKDIwMTgpCgpgYGB7cn0KIyBGaW5kIGNsdXN0ZXIgYXZlcmFnZXMgb2YgaHVtYW4gbGl2ZXIgZGF0YQpsb2FkKCJ+L0Ryb3Bib3gvWm9lL3NjZl92ZXJzaW9uL2FuYWx5c2lzL2NvcnJlbGF0aW9uVGVzdHMvSHVtYW5MaXZlci5SRGF0YSIpCiMgUnVuIFNDVHJhbnNmb3JtCkh1bWFuTGl2ZXJTZXVyYXQgPC0gVXBkYXRlU2V1cmF0T2JqZWN0KEh1bWFuTGl2ZXJTZXVyYXQpCkh1bWFuTGl2ZXJTZXVyYXQgPC0gU0NUcmFuc2Zvcm0oSHVtYW5MaXZlclNldXJhdCkKaHVtYW5DbHVzdGVyQXZlcmFnZXMgPC0gQXZlcmFnZUV4cHJlc3Npb24oSHVtYW5MaXZlclNldXJhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXlzID0gIlNDVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QgPSAic2NhbGUuZGF0YSIpCiMgUmVwbGFjZSBjbHVzdGVyIG51bWJlcnMgd2l0aCBuYW1lcwpjb2xuYW1lcyhodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpIDwtIGMoIkhlcCAxIiwgIkFscGhhLWJldGEgVCBjZWxscyIsICJIZXAgMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW5mbGFtbWF0b3J5IG1hY3MiLCAiSGVwIDMiLCAiSGVwIDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBsYXNtYSBjZWxscyIsICJOSy1saWtlIGNlbGxzIiwgIkdhbW1hLWRlbHRhIFQgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbi1pbmZsYW1tYXRvcnkgbWFjcyIsICJQZXJpcG9ydGFsIExTRUNzIiwgIkNlbnRyYWwgdmVub3VzIExTRUNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3J0YWwgZW5kb3RoZWxpYWwgY2VsbHMiLCAiSGVwIDUiLCAiSGVwIDYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hdHVyZSBCIGNlbGxzIiwgIkNob2xhbmdpb2N5dGVzIiwgIkdhbW1hLWRlbHRhIFQgY2VsbHMgMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXJ5dGhyb2lkIGNlbGxzIiwgIkhlcGF0aWMgc3RlbGxhdGUgY2VsbHMiKQojIElmIG9ubHkgbG9va2luZyBhdCBzcGVjaWZpYyBjbHVzdGVycwojaHVtYW5DbHVzdGVyQXZlcmFnZXMkU0NUIDwtIGh1bWFuQ2x1c3RlckF2ZXJhZ2VzJFNDVFssYygiMyIsIjEiLCIxNSIsIjYiLCIxNCIsIjUiKV0KIyBPdGhlcndpc2UgZ28gc3RyYWlnaHQgdG8gaGVyZToKaHVtYW5DbHVzdGVyQXZlcmFnZXMkU0NUIDwtIG5hLm9taXQodChzY2FsZSh0KGFzLm1hdHJpeChodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpKSkpKQojIEdyYWIgZ2VuZSBuYW1lcwpodW1hbkdlbmVzIDwtIHJvdy5uYW1lcyhodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpCiMgTm93IHR1cm4gaW50byBsYXJnZSBkYXRhZnJhbWUKYWxsQ2VsbHNNYXRyaXggPC0gYXMuZGF0YS5mcmFtZShodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpCiMgT3JkZXIgYnkgcm93IG5hbWUKYWxsQ2VsbHNNYXRyaXggPC0gYWxsQ2VsbHNNYXRyaXhbb3JkZXIocm93Lm5hbWVzKGFsbENlbGxzTWF0cml4KSksXQojIFNhbml0eSBjaGVjawpoZWFkKGFsbENlbGxzTWF0cml4KQpzcGVjaWVzRGF0YSA8LSAibWFjcGFybGFuZCIKYGBgCgpDb3JyZWxhdGlvbiBvZiB3b29kY2h1Y2sgbGl2ZXIgd2l0aCBodW1hbiBsaXZlciBkYXRhc2V0IGZyb20gQWl6YXJhbmkgKmV0IGFsLioKCmBgYHtyfQojIFJlYWQgaW4gQWl6YXJhbmkgZGF0YXNldAphaXphcmFuaSA8LSByZWFkUkRTKCJ+L0Ryb3Bib3gvWm9lL3NjZl92ZXJzaW9uL2FuYWx5c2lzL2NvcnJlbGF0aW9uVGVzdHMvR1NFMTI0Mzk1X05vcm1hbGh1bWFubGl2ZXJkYXRhLlJEYXRhIikKIyBSZWFkIGluIGNsdXN0ZXJzIGFuZCBsYWJlbCBjZWxscwphaXphcmFuaUNsdXN0ZXJzIDwtIHJlYWQudGFibGUoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvY29ycmVsYXRpb25UZXN0cy9HU0UxMjQzOTVfY2x1c3RlcnBhcnRpdGlvbi50eHQiKQojIE9ubHkga2VlcCBjZWxscyBpbiB0aGUgY2x1c3RlciBvYmplY3QKYWl6YXJhbmkgPC0gYWl6YXJhbmlbLGludGVyc2VjdChjb2xuYW1lcyhhaXphcmFuaSkscm93Lm5hbWVzKGFpemFyYW5pQ2x1c3RlcnMpKV0KIyBDcmVhdGUgU2V1cmF0IG9iamVjdAphaXphcmFuaSA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gYWl6YXJhbmkpCiMgUnVuIFNDVHJhbnNmb3JtCmFpemFyYW5pIDwtIFNDVHJhbnNmb3JtKGFpemFyYW5pKQojIEFkZCBjbHVzdGVyIElEcwpJZGVudHMoYWl6YXJhbmkpIDwtIGFpemFyYW5pQ2x1c3RlcnMkc2N0LmNwYXJ0CiMgR2V0IGNsdXN0ZXIgYXZlcmFnZXMKYWl6YXJhbmlBdmVyYWdlcyA8LSBBdmVyYWdlRXhwcmVzc2lvbihhaXphcmFuaSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheXMgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gInNjYWxlLmRhdGEiKQphaXphcmFuaUF2ZXJhZ2VzJFNDVCA8LSBuYS5vbWl0KHQoc2NhbGUodChhcy5tYXRyaXgoYWl6YXJhbmlBdmVyYWdlcyRTQ1QpKSkpKQojIEdyYWIgZ2VuZSBuYW1lcwphaXphcmFuaUdlbmVzIDwtIHJvdy5uYW1lcyhhaXphcmFuaUF2ZXJhZ2VzJFNDVCkKIyBOb3cgdHVybiBpbnRvIGxhcmdlIGRhdGFmcmFtZQphbGxDZWxsc01hdHJpeCA8LSBhcy5kYXRhLmZyYW1lKGFpemFyYW5pQXZlcmFnZXMkU0NUKQojIE9yZGVyIGJ5IGNvbHVtbgphbGxDZWxsc01hdHJpeCA8LSBhbGxDZWxsc01hdHJpeFssYXMuY2hhcmFjdGVyKHNvcnQoYXMubnVtZXJpYyhjb2xuYW1lcyhhbGxDZWxsc01hdHJpeCkpKSldCiMgUmVuYW1lIGNvbHVtbnMgdG8gYmUgbW9yZSBtZWFuaW5nZnVsIChub3QgdG90YWxseSBjb25maWRlbnQgSSBnb3QgYWxsIGNvcnJlY3QpCmNvbG5hbWVzKGFsbENlbGxzTWF0cml4KSA8LSBjKCdOSywgTktUIGFuZCBUIGNlbGxzICgxKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdLdXBmZmVyIGNlbGxzICgyKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdOSywgTktUIGFuZCBUIGNlbGxzICgzKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdFUENBTSsgY2VsbHMgYW5kIGNob2xhbmdpb2N5dGVzICg0KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdOSywgTktUIGFuZCBUIGNlbGxzICg1KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdLdXBmZmVyIGNlbGxzICg2KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdFUENBTSsgY2VsbHMgYW5kIGNob2xhbmdpb2N5dGVzICg3KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdCIGNlbGxzICg4KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMaXZlciBzaW51c29pZGFsIGVuZG90aGVsaWFsIGNlbGxzICg5KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNYWNyb3Zhc2N1bGFyIGVuZG90aGVsaWFsIGNlbGxzICgxMCknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSGVwYXRvY3l0ZXMgKDExKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdOSywgTktUIGFuZCBUIGNlbGxzICgxMiknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTGl2ZXIgc2ludXNvaWRhbCBlbmRvdGhlbGlhbCBjZWxscyAoMTMpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0hlcGF0b2N5dGVzICgxNCknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnT3RoZXIgZW5kb3RoZWxpYWwgY2VsbHMgKDE1KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPdGhlciAoMTYpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0hlcGF0b2N5dGVzICgxNyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTkssIE5LVCBhbmQgVCBjZWxscyAoMTgpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ05LLCBOS1QgYW5kIFQgY2VsbHMgKDE5KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMaXZlciBzaW51c29pZGFsIGVuZG90aGVsaWFsIGNlbGxzICgyMCknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTWFjcm92YXNjdWxhciBlbmRvdGhlbGlhbCBjZWxscyAoMjEpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0IgY2VsbHMgKDIyKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdLdXBmZmVyIGNlbGxzICgyMyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRVBDQU0rIGNlbGxzIGFuZCBjaG9sYW5naW9jeXRlcyAoMjQpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0t1cGZmZXIgY2VsbHMgKDI1KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPdGhlciBlbmRvdGhlbGlhbCBjZWxscyAoMjYpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ090aGVyICgyNyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTkssIE5LVCBhbmQgVCBjZWxscyAoMjgpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01hY3JvdmFzY3VsYXIgZW5kb3RoZWxpYWwgY2VsbHMgKDI5KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdIZXBhdG9jeXRlcyAoMzApJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0t1cGZmZXIgY2VsbHMgKDMxKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNYWNyb3Zhc2N1bGFyIGVuZG90aGVsaWFsIGNlbGxzICgzMiknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnU3RlbGxhdGUgY2VsbHMgYW5kIG15b2ZpYnJvYmxhc3RzICgzMyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQiBjZWxscyAoMzQpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ090aGVyIGVuZG90aGVsaWFsIGNlbGxzICgzNSknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnT3RoZXIgKDM2KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPdGhlciAoMzcpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0IgY2VsbHMgKDM4KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdFUENBTSsgY2VsbHMgYW5kIGNob2xhbmdpb2N5dGVzICgzOSknKQojIE9yZGVyIGJ5IHJvdyBuYW1lCmFsbENlbGxzTWF0cml4IDwtIGFsbENlbGxzTWF0cml4W29yZGVyKHJvdy5uYW1lcyhhbGxDZWxsc01hdHJpeCkpLF0KIyBTYW5pdHkgY2hlY2sKaGVhZChhbGxDZWxsc01hdHJpeCkKc3BlY2llc0RhdGEgPC0gImFpemFyYW5pIgpgYGAKCkNvcnJlbGF0aW9uIG9mIHdvb2RjaHVjayBsaXZlciB3aXRoIHdvb2RjaHVjayBQQk1Dcy4gRm9yIHRoaXMgY29ycmVsYXRpb24sIHJlYWQgaW4gdGhlIHdvb2RjaHVjayBsaXZlciBkYXRhc2V0IGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhpcyBzY3JpcHQgYW5kIHRoZW4gcmVhZCBpbiB0aGUgd29vZGNodWNrIFBCTUNzIGJlbG93CgpgYGB7cn0KZ3JvdXBzIDwtICJnZW5lcmFsX2NlbGxfbGFiZWxzIgojIFN0YXJ0IHdpdGggbGl2ZXIgYW5kIHJlYWQgaW4gd29vZGNodWNrIFBCTUNzIGFnYWluCmxvYWQoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvaGVhbHRoeV9zYy9zZXVyYXRfb2JqZWN0cy9ub19kcm9wbGV0UUMvaW50ZWdyYXRlZF9QQk1DX2NjYV9rYW5jaG9yNV9zY0NsdXN0Vml6LlJEYXRhIikKSWRlbnRzKHNjU2V1cmF0KSA8LSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuNiIKIyBGaW5kIGNsdXN0ZXIgYXZlcmFnZXMKcGJtY0NsdXN0ZXJBdmVyYWdlcyA8LSBBdmVyYWdlRXhwcmVzc2lvbihzY1NldXJhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheXMgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gInNjYWxlLmRhdGEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gZ3JvdXBzKQpwYm1jQ2x1c3RlckF2ZXJhZ2VzIDwtIGFzLmRhdGEuZnJhbWUobmEub21pdCh0KHNjYWxlKHQoYXMubWF0cml4KHBibWNDbHVzdGVyQXZlcmFnZXMkU0NUKSkpKSkpCiMgT3JkZXIgYnkgcm93IG5hbWUKYWxsQ2VsbHNNYXRyaXggPC0gcGJtY0NsdXN0ZXJBdmVyYWdlc1tvcmRlcihyb3cubmFtZXMocGJtY0NsdXN0ZXJBdmVyYWdlcykpLF0Kc3BlY2llc0RhdGEgPC0gIlBCTUMiCmBgYAoKIyMjIE91dHB1dCBwbG90cyBmb3IgYWxsIGNvcnJlbGF0aW9ucwoKYGBge3J9CiMgTm93IGZpbmQgaW50ZXJzZWN0aW5nIGdlbmVzCm1hdGNoZXMgPC0gaW50ZXJzZWN0KHJvdy5uYW1lcyhhbGxDZWxsc01hdHJpeCksCiAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyh3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMpKQojIExvb2sgYXQgaG93IG1hbnkgZ2VuZXMgbWF0Y2hlZApsZW5ndGgobWF0Y2hlcykKIyBNYWtlIG5ldyBtYXRyaWNlcyB3aXRoIG9ubHkgbWF0Y2hpbmcgZ2VuZSBuYW1lcwp0b0NvciA8LSBhbGxDZWxsc01hdHJpeFttYXRjaGVzLF0Kd29vZGNodWNrQXZlcmFnZXNDb3IgPC0gd29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzW21hdGNoZXMsXQojIERvIFBlYXJzb24KcGVhclZhbCA8LSBjb3IodG9Db3IsIHdvb2RjaHVja0F2ZXJhZ2VzQ29yLCBtZXRob2QgPSAicGVhcnNvbiIpCmhlYXRtYXAocGVhclZhbCkKICAgICAgICAjbWFpbiA9IHBhc3RlKCJQZWFyc29uIGNvcnJlbGF0aW9uIG9mIiwgc3BlY2llc0RhdGEsICJ2cyIsIHdvb2RjaHVja0RhdGEpLAogICAgICAgICN4bGFiID0gd29vZGNodWNrRGF0YSwKICAgICAgICAjeWxhYiA9IHNwZWNpZXNEYXRhKQogICAgICAgICNtYXJnaW5zID0gYyg2LDExKSkKI1Jvd3YgPSBOQSwKI0NvbHYgPSBOQSkKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl8iLCBzcGVjaWVzRGF0YSwgIl9QZWFyc29uQ29yLnBkZiIsIHNlcCA9ICIiKSwKICAgIGhlaWdodCA9IDEzLCB3aWR0aCA9IDEzKQpoZWF0bWFwKHBlYXJWYWwsIG1hcmdpbnMgPSBjKDEzLDEzKSkKZGV2Lm9mZigpCiMgRG8gU3BlYXJtYW4Kc3BlYXJWYWwgPC0gY29yKHRvQ29yLCB3b29kY2h1Y2tBdmVyYWdlc0NvciwgbWV0aG9kID0gInNwZWFybWFuIikKaGVhdG1hcChzcGVhclZhbCkKICAgICAgICAjbWFpbiA9IHBhc3RlKCJTcGVhcm1hbiBjb3JyZWxhdGlvbiBvZiIsIHNwZWNpZXNEYXRhLCAidnMiLCB3b29kY2h1Y2tEYXRhKSwKICAgICAgICAjeGxhYiA9IHdvb2RjaHVja0RhdGEsCiAgICAgICAgI3lsYWIgPSBzcGVjaWVzRGF0YSkKICAgICAgICAjbWFyZ2lucyA9IGMoNiwxMSkpCiNSb3d2ID0gTkEsCiNDb2x2ID0gTkEpCnBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfIiwgc3BlY2llc0RhdGEsICJfU3BlYXJtYW5Db3IucGRmIiwgc2VwID0gIiIpLAogICAgaGVpZ2h0ID0gMTMsIHdpZHRoID0gMTMpCmhlYXRtYXAoc3BlYXJWYWwsIG1hcmdpbnMgPSBjKDEzLDEzKSkKZGV2Lm9mZigpCmBgYAoKCgoK